/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.entityGenerator.base.dataTypeData;

import com.inspur.edp.caf.generator.BaseGenerator;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.item.InterfaceGenerator;
import com.inspur.edp.caf.generator.item.InterfaceGeneratorContext;
import com.inspur.edp.caf.generator.property.InterfacePropertyGenerator;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.gencommon.MediateType;
import com.inspur.edp.cef.generator.entityGenerator.base.DataTypeGeneratorContext;
import com.inspur.edp.cef.generator.entityGenerator.base.dataTypeData.dataTypePropGen.DynamicPropSetPropertyGenerator;
import com.inspur.edp.cef.generator.entityGenerator.base.dataTypeData.dataTypePropGen.NormalDataPropertyGenerator;
import com.inspur.edp.cef.generator.entityGenerator.base.dataTypeData.dataTypePropGen.UdtDataPropertyGenerator;
import com.inspur.edp.cef.generator.entityGenerator.base.dataTypeData.dataTypePropGen.assoUdt.AssoUdtDataPropertyGenerator;
import com.inspur.edp.cef.generator.overall.Utils;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.Modifier;

public abstract class DataTypeDataGenerator extends InterfaceGenerator {
	protected final DataTypeGeneratorContext nodeGenContext;

	protected DataTypeDataGenerator(DataTypeGeneratorContext nodeGenContext, IGspCommonDataType dataType) {
		super(nodeGenContext.getEntityGenContext().getCompilationUnitInfo());
		this.nodeGenContext = nodeGenContext;
		this.dataType = dataType;
	}

	private IGspCommonDataType dataType;

	protected final IGspCommonDataType getDataType() {
		return dataType;
	}

	protected DataTypeDataGeneratorContext getContext() {
		return (DataTypeDataGeneratorContext) ((super.getContext() instanceof DataTypeDataGeneratorContext) ? super.getContext() : null);
	}

	@Override
	protected InterfaceGeneratorContext createInterfaceItemContext() {
		DataTypeDataGeneratorContext context = createDataTypeDataGenContext();
		context.setDataType(getDataType().getClass());
		nodeGenContext.setDataGenContext(context);
		nodeGenContext.getEntityGenContext().getDataTypeDataGenContexts().put(dataType.getCode(), context);
		return context;
	}

	protected DataTypeDataGeneratorContext createDataTypeDataGenContext() {
		return new DataTypeDataGeneratorContext(nodeGenContext);
	}

	@Override
	protected ArrayList<Modifier.ModifierKeyword> getAccessModifier() {
		return new ArrayList<Modifier.ModifierKeyword>(java.util.Arrays.asList(
				new Modifier.ModifierKeyword[]{Modifier.ModifierKeyword.PUBLIC_KEYWORD}));
	}

	@Override
	protected String getName() {
		return getName(getDataType());
	}

	@Override
	protected ArrayList<BaseGenerator> createChildGenerators() {
		ArrayList<BaseGenerator> list = super.createChildGenerators();
		if (list == null) {
			list = new ArrayList<BaseGenerator>();
		}
		list.addAll(createPropertyGenerators());
		ArrayList<BaseGenerator> extendGenrators = createDataTypeExtendGenerators();
		if (extendGenrators != null) {
			list.addAll(extendGenrators);
		}
		return list;
	}

	private ArrayList<BaseGenerator> createPropertyGenerators() {
		java.util.ArrayList<BaseGenerator> rez = new java.util.ArrayList<BaseGenerator>();
		// 单值关联
		if (getContext().getDataType() == SimpleDataTypeDef.class && ((SimpleDataTypeDef) getDataType()).getObjectType() == GspElementObjectType.Association) {
			if (getDataType().getContainElements() == null || getDataType().getContainElements().size() != 1) {
				throw new RuntimeException();
			}
			IGspCommonField ele = getDataType().getContainElements().get(0);
			rez.addAll(getDataTypePropertyGenerators(ele, getContext()));
			if (ele.getChildAssociations() == null || ele.getChildAssociations().get(0).getRefElementCollection() == null || ele.getChildAssociations().get(0).getRefElementCollection().size() == 0) {
				throw new RuntimeException("单值关联类型的业务字段'{ele.getCode()}'关联信息不完整。");
			}
			// assoUdt_ID
			rez.add(getAssoUdtItemPropertyGenerator(ele.getLabelID(), ele));

			for (IGspCommonField refEle : ele.getChildAssociations().get(0).getRefElementCollection()) {
				if ((ele.getLabelID() + "_ID").equals(refEle.getLabelID())) {
					continue;
				}
				AssoUdtItemPropertyGenerator assoItemGen = getAssoUdtItemPropertyGenerator(ele.getLabelID(), refEle);
				rez.add(assoItemGen);
			}
		} else {
			for (IGspCommonField element : getDataType().getContainElements()) {
				if (createFieldPropertyGenerator(element) == false) {
					continue;
				}
				rez.addAll(getDataTypePropertyGenerators(element, getContext()));
			}
		}
		return rez;
	}


	protected ArrayList<BaseGenerator> createDataTypeExtendGenerators() {
		return null;
	}

	public InterfacePropertyGenerator getDataTypePropertyGenerator(IGspCommonField field, DataTypeDataGeneratorContext Context) {
		if (field.getObjectType() == GspElementObjectType.DynamicProp) //动态属性字段
		{
			return new DynamicPropSetPropertyGenerator(field, Context);
		} else if (field.getIsUdt()) //udt字段
		{
			UnifiedDataTypeDef udtDef = null;
			try {
				udtDef = (UnifiedDataTypeDef) Context.getDataTypeGeneratorContext().
						getEntityGenContext().getCefGenContext().
						getMetadataJitContext().getMetadata(field.getUdtID()).getContent();
				//udtDef = (UnifiedDataTypeDef) CefGenServiceManager.getLcmDtService().getRefMetadata(field.getUdtID()).getContent();
			} catch (Exception e) {
				throw new RuntimeException("获取udt元数据"+field.getUdtID()+"失败",e);
			}
			//单值关联udt
			SimpleDataTypeDef sdtDef = (SimpleDataTypeDef) ((udtDef instanceof SimpleDataTypeDef) ? udtDef : null);
			if (sdtDef != null && sdtDef.getObjectType() == GspElementObjectType.Association && field.containRefElementNotFromAssoUdt()) {
				return new AssoUdtDataPropertyGenerator(field, (SimpleDataTypeDef) udtDef, Context);
			}
			//其他Udt
			return new UdtDataPropertyGenerator(field, udtDef, Context);
		} else //普通字段
		{
			return getNormalDataPropertyGenerator(field, Context);
		}
	}

	public List<InterfacePropertyGenerator> getDataTypePropertyGenerators(IGspCommonField field,
			DataTypeDataGeneratorContext Context) {
		List<InterfacePropertyGenerator> interfacePropertyGenerators = new ArrayList<InterfacePropertyGenerator>();
		if (field.getObjectType() == GspElementObjectType.DynamicProp) //动态属性字段
		{
			interfacePropertyGenerators.add(new DynamicPropSetPropertyGenerator(field, Context));
			return interfacePropertyGenerators;
		} else if (field.getIsUdt()) //udt字段
		{
			UnifiedDataTypeDef udtDef = null;
			try {
				udtDef = (UnifiedDataTypeDef) Context.getDataTypeGeneratorContext().
						getEntityGenContext().getCefGenContext().
						getMetadataJitContext().getMetadata(field.getUdtID()).getContent();
				//udtDef = (UnifiedDataTypeDef) CefGenServiceManager.getLcmDtService().getRefMetadata(field.getUdtID()).getContent();
			} catch (Exception e) {
				//销售订单上的销售订单节点中销售地点字段是业务字段类型的,
				//但是查找它对应的业务字段不存在, 业务字段名称为:地址, ID为:xxx
				throw new RuntimeException("获取udt元数据" + field.getUdtID() + "失败", e);
			}
			//单值关联udt
			SimpleDataTypeDef sdtDef = (SimpleDataTypeDef) ((udtDef instanceof SimpleDataTypeDef) ? udtDef
					: null);
			if (sdtDef != null && sdtDef.getObjectType() == GspElementObjectType.Association && field
					.containRefElementNotFromAssoUdt()) {
				interfacePropertyGenerators
						.add(new AssoUdtDataPropertyGenerator(field, (SimpleDataTypeDef) udtDef, Context));
			} else {
				//其他Udt
				interfacePropertyGenerators.add(new UdtDataPropertyGenerator(field, udtDef, Context));
			}
			return interfacePropertyGenerators;
		} else //普通字段
		{
			interfacePropertyGenerators.add(getNormalDataPropertyGenerator(field, Context, false));
			if (!field.getLabelID().equals(Utils.toUpperCaseFirstOne(field.getLabelID()))) {
				interfacePropertyGenerators.add(getNormalDataPropertyGenerator(field, Context, true));
			}
			return interfacePropertyGenerators;
		}
	}

	protected NormalDataPropertyGenerator getNormalDataPropertyGenerator(IGspCommonField field,
	                                                                     DataTypeDataGeneratorContext Context) {
		return getNormalDataPropertyGenerator(field, Context, false);
	}

	protected NormalDataPropertyGenerator getNormalDataPropertyGenerator(IGspCommonField field,
																		 DataTypeDataGeneratorContext Context, boolean toUpper) {
		return new NormalDataPropertyGenerator(field, Context, toUpper);
	}

	private AssoUdtItemPropertyGenerator getAssoUdtItemPropertyGenerator(String parentPropName, IGspCommonField field) {
		return new AssoUdtItemPropertyGenerator(parentPropName, field, getContext());
	}

	protected boolean createFieldPropertyGenerator(IGspCommonField field) {
		if (field.getIsRef()) {
			return false;
		}
		return true;
	}

	@Override
	protected final void afterGenerate() {
		super.afterGenerate();
		nodeGenContext.getEntityGenContext().getNodeTypes().
				put(getDataType().getCode(), new MediateType(nodeGenContext.getEntityGenContext().getDefaultPackageName(), getName()));
		dataTypeDataAfterGenerate();
	}

	protected void dataTypeDataAfterGenerate() {
	}

	@Override
	protected ArrayList<TypeInfo> addParentInterfaces() {
		ArrayList<TypeInfo> rez = new ArrayList<TypeInfo>();
		//if (DataType.EnableDynamicProp)
		//    rez.add(typeof(IDynamicPropSetHost));
		ArrayList<TypeInfo> extendsInterfaces = addExtendParentInterfaces();
		if (extendsInterfaces != null) {
			rez.addAll(extendsInterfaces);
		}
		return rez;
	}


	protected ArrayList<TypeInfo> addExtendParentInterfaces() {
		return null;
	}


	// region Static Members
	public static String getName(IGspCommonDataType node) {
		return node.getGeneratedEntityClassInfo().getClassName();
	}
	// endregion
}
